package com.suieqian.handler;

import cn.hutool.core.util.StrUtil;
import com.suieqian.exception.NoAuthException;
import com.suieqian.util.Message;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 全局异常处理器，将 Exception 翻译成 Message + 对应的异常编号
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 处理 SpringMVC 请求方法不正确
     * <p>
     * 例如说，A 接口的方法为 GET 方式，结果请求方法为 POST 方式，导致不匹配
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Message httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException ex) {
        log.warn("[httpRequestMethodNotSupportedExceptionHandler]", ex);
        return Message.httpError(String.format("请求方法不正确:%s", ex.getMessage()));
    }

    @ExceptionHandler(NoAuthException.class)
    public Message httpRequestNoAuthExceptionHandler(NoAuthException ex) {
        log.warn("[NoAuthException]", ex);
        return Message.authError("请先登录");
    }

    /**
     * ConstraintViolationException 校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Message handleUnexpectedTypeException(ConstraintViolationException e) {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotBlank(e.getMessage())) {
            String[] strArr = e.getMessage().split(",");
            for (int i = 0; i < strArr.length; i++) {
                sb.append(strArr[i].split(": ")[1]).append("；  ");
            }
        }
        log.error("发生传参-Variable（GET校验）-异常！原因是：{}", sb.toString());
        return Message.error(Message.PARAMETER_ERROR, sb.toString());
    }

    /**
     * BindException 校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Message handleBindException(BindException e) {
        final BindingResult bindingResult = e.getBindingResult();
        final List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
        final String message;
        if (CollectionUtils.isEmpty(fieldErrorList)) {
            message = "参数不符合规范";
        } else {
            message =
                    fieldErrorList.stream()
                            .map(DefaultMessageSourceResolvable::getDefaultMessage)
                            .filter(StrUtil::isNotBlank)
                            .distinct()
                            .collect(Collectors.joining("；  "));
        }
        log.error("发生传参-Variable（POST校验）-异常！原因是：{}", message);
        return Message.error(Message.PARAMETER_ERROR, message);
    }

    /**
     * 处理系统异常，兜底处理所有的一切
     */
    @ExceptionHandler(value = Exception.class)
    public Message defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
        log.error("[defaultExceptionHandler]", ex);
        // 返回 ERROR CommonResult
        return Message.error(ex.getMessage());
    }


}
